package cn.changeforyou.devUtils.copy;

import cn.changeforyou.utils.convert.twoDimensionalTable.TwoDimensionalTableUtil;
import cn.changeforyou.utils.jcommander.JcommanderService;
import cn.changeforyou.utils.validator.ValidatorUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.file.PathUtil;
import cn.hutool.core.text.csv.*;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

/**
 * -s J:\test\Resin补丁 -t J:\test\Resin  -b J:\test\备份
 * -s J:\test\文档V2.txt -t J:\test\文档V1.txt -b J:\test\备份
 * -h
 *
 * @author zhyu
 * @version 1.0
 * @date 2022-7-15 10:36
 */
@Slf4j
public class CopyService implements JcommanderService<Parameters> {

    private CopyContext copyContext;
    private RecoveryContext recoveryContext;
    final static String COPY_LOG_NAME = "copyLog.csv";
    final static String RECOVERY_LOG_NAME = "recoveryLog.csv";

    @Override
    public void execute(Parameters params) {
        Mode mode = params.getMode();

        if (mode == Mode.copy) {
            dealCopy(params);
        } else {
            dealRecovery(params);
        }
    }

    /**
     * 处理恢复模式
     */
    private void dealRecovery(Parameters params) {
        String copyLogPath = params.getCopyLogPath();
        if (StrUtil.isNotBlank(copyLogPath)) {
            dealRecoveryInCopyLogMode(params, copyLogPath);
        } else {
            dealRecoveryInCompareMode(params);
        }
    }

    /**
     * 比较还原模式
     * 要求三路径有效(src,target, backup)
     * 不根据copyLog还原
     */
    private void dealRecoveryInCompareMode(Parameters params) {
        initRecoveryContextAndValid(params);

        dealRelativePath(recoveryContext);
        scanFiles();

        recovery();

        //日志
        printRecoveryLog();
    }

    /**
     * 扫描文件夹
     */
    private void scanFiles() {
        final List<RecoveryFileInfo> recoveryFileInfos = recoveryContext.getRecoveryFileInfos();
        String srcPath = recoveryContext.getSrcPath();
        final Path srcPathObj = Paths.get(srcPath);
        final String targetPath = recoveryContext.getTargetPath();
        final String backPath = recoveryContext.getBackPath();
        FileUtil.walkFiles(srcPathObj, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)
                    throws IOException {
                RecoveryFileInfo info = new RecoveryFileInfo();
                recoveryFileInfos.add(info);
                info.setSrcFilePath(PathUtil.toAbsNormal(path).toString());
                info.setSrcFileFind(true);
                info.setSrcFile(path.toFile());

                Path relativize = srcPathObj.relativize(path);
                Path targetPathObject = Paths.get(targetPath, relativize.toString());
                info.setTargetFilePath(PathUtil.toAbsNormal(targetPathObject).toString());
                boolean targetExist = PathUtil.exists(targetPathObject, true);
                if(targetExist){
                    info.setTargetFileFind(true);
                    info.setTargetFile(targetPathObject.toFile());
                }
                Path backupPathObject = Paths.get(backPath, relativize.toString());
                info.setBackFilePath(PathUtil.toAbsNormal(backupPathObject).toString());
                boolean backupExist = PathUtil.exists(backupPathObject, true);
                if(backupExist){
                    info.setBackFileFind(true);
                    info.setBackFile(backupPathObject.toFile());
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 初始化上下文并且校验路径有效性
     */
    private void initRecoveryContextAndValid(Parameters params) {
        ValidatorUtils.valid(params, ValidConstant.Recovery.class);
        log.info("进入比较恢复模式,  源原件路径:{}, 目标路径:{}, 备份路径:{}", params.getSrcPath(), params.getTargetPath(), params.getBackupDirectory());

        File srcFile = new File(params.getSrcPath());
        if (!srcFile.exists()) {
            throw new CopyException("路径[" + params.getSrcPath() + "]没找到");
        }
        File targetFile = new File(params.getTargetPath());
        if (!targetFile.exists()) {
            throw new CopyException("路径[" + params.getTargetPath() + "]没找到");
        }
        File backupFile = new File(params.getBackupDirectory());
        if (!backupFile.exists()) {
            throw new CopyException("路径[" + params.getBackupDirectory() + "]没找到");
        }

        //比较src和backup区域, 清理出recoveryFileInfos(还原信息文件列表)
        recoveryContext = new RecoveryContext();
        recoveryContext.setMode(1);
        recoveryContext.setSrcPath(params.getSrcPath());
        recoveryContext.setTargetPath(params.getTargetPath());
        recoveryContext.setBackPath(params.getBackupDirectory());
        recoveryContext.setRecoveryLogPath(params.getRecoveryLogPath());
    }

    /**
     * 日志还原模式
     * 要求copyLog有效
     * 根据copyLog还原
     */
    private void dealRecoveryInCopyLogMode(Parameters params, String copyLogPath) {
        log.info("正在进行文件恢复, 日志恢复模式");
        //src地址,target地址, backup地址
        Path copyLogPathObject = Paths.get(copyLogPath, COPY_LOG_NAME);
        if (!PathUtil.exists(copyLogPathObject, true)) {
            throw new CopyException("路径[" + copyLogPathObject + "]没找到");
        }

        recoveryContext = new RecoveryContext();
        recoveryContext.setCopyLogPath(copyLogPath);
        recoveryContext.setCopyLogPathObject(copyLogPathObject);
        recoveryContext.setRecoveryLogPath(params.getRecoveryLogPath());
        parseCopyLog();

        //解析全文件清单且加入backup信息
        loadFile();

        recovery();

        //日志
        printRecoveryLog();
    }

    /**
     * 打印还原日志
     */
    private void printRecoveryLog() {
        String now = DateUtil.now();

        String csvPath = Paths.get(recoveryContext.getRecoveryLogPath(), RECOVERY_LOG_NAME).toAbsolutePath().normalize().toString();
        CsvWriter csvWriter = new CsvWriter(csvPath, CharsetUtil.CHARSET_GBK);
        List<String[]> csvData = new ArrayList<>();
        csvData.add(new String[]{"文件名", "是否需要替换", "是否替换成功", "是否需要删除", "是否删除成功", "替换源路径"});
        List<RecoveryFileInfo> recoveryFileInfos = recoveryContext.getRecoveryFileInfos();
        int overrideErrorCount = 0;
        int deleteErrorCount = 0;
        int targetFileNotFountCount = 0;
        Collections.sort(recoveryFileInfos, Comparator.reverseOrder());
        for (RecoveryFileInfo info : recoveryFileInfos) {
            String[] csvRow = new String[6];
            csvData.add(csvRow);
            if (info.isNeedOverride() && !info.isOverrideSuccess()) {
                overrideErrorCount++;
            }
            if (info.isNeedDelete() && !info.isDeleteSuccess()) {
                deleteErrorCount++;
            }
            if (!info.isNeedOverride() && !info.isNeedDelete()) {
                targetFileNotFountCount++;
            }

            csvRow[0] = TwoDimensionalTableUtil.defaultValue(info.getTargetFilePath());
            csvRow[1] = TwoDimensionalTableUtil.defaultValue(BooleanUtil.toStringYesNo(info.isNeedOverride()));
            csvRow[2] = TwoDimensionalTableUtil.defaultValue(BooleanUtil.toStringYesNo(info.isOverrideSuccess()));
            csvRow[3] = TwoDimensionalTableUtil.defaultValue(BooleanUtil.toStringYesNo(info.isNeedDelete()));
            csvRow[4] = TwoDimensionalTableUtil.defaultValue(BooleanUtil.toStringYesNo(info.isDeleteSuccess()));
            csvRow[5] = TwoDimensionalTableUtil.defaultValue(info.getOverridePath());
        }

        csvWriter.write(new String[]{"还原器版", "还原时间", "还原模式", "复制日志路径", "srcPath", "targetPath", "backupPath"});
        csvWriter.write(new String[]{"v1.0", now, recoveryContext.getModeString(), TwoDimensionalTableUtil.defaultValue(recoveryContext.getCopyLogPath()), recoveryContext.getSrcPath(), recoveryContext.getTargetPath(), recoveryContext.getBackPath()});
        csvWriter.writeComment(String.format("文件总数:%d; 未找到文件数:%d; 替换失败数: %d; 删除失败数:%d", recoveryFileInfos.size(), targetFileNotFountCount, overrideErrorCount, deleteErrorCount));

        for (String[] csvDatum : csvData) {
            csvWriter.write(csvDatum);
        }
        boolean success = overrideErrorCount + deleteErrorCount + targetFileNotFountCount == 0;
        if (success) {
            log.info("全部还原成功,详情见{}", csvPath);
        } else {
            log.info("还原有失败的之处, 详情请看日志:{}", csvPath);
        }
    }

    /**
     * 还原操作
     */
    private void recovery() {
        List<RecoveryFileInfo> recoveryFileInfos = recoveryContext.getRecoveryFileInfos();
        for (RecoveryFileInfo info : recoveryFileInfos) {
            if (info.isTargetFileFind()) {
                if (info.isBackFileFind()) {
                    //target和backup都有的替换
                    try {
                        info.setNeedOverride(true);
                        FileUtil.copy(info.getBackFile(), info.getTargetFile(), true);
                        info.setOverrideSuccess(true);
                        log.error("复制{}替换{}成功", info.getBackFilePath(), info.getTargetFilePath());
                        ;
                    } catch (IORuntimeException e) {
                        log.error("替换失败", e);
                        log.error("复制{}替换{}失败,异常:{}", info.getBackFilePath(), info.getTargetFilePath(), e.getMessage());
                    }
                } else {
                    //只有target就删除
                    try {
                        info.setNeedDelete(true);
                        boolean del = FileUtil.del(info.getTargetFile());
                        if (del) {
                            info.setDeleteSuccess(true);
                            log.error("删除文件{}成功", info.getTargetFilePath());
                        } else {
                            info.setErrorMessage("未知原因删除失败");
                            log.error("删除文件{}失败", info.getTargetFilePath());
                        }
                    } catch (IORuntimeException e) {
                        info.setErrorMessage(e.getMessage());
                        log.error("删除失败", e);
                        log.error("删除文件{}失败", info.getTargetFilePath());
                    }
                }
            }
        }
    }

    /**
     * 解析全文件清单且加入backup信息
     * 根据recoveryFileInfos加载文件, 要求copySuccess有值甚至backSuccess有值才有意义
     */
    private void loadFile() {
        List<RecoveryFileInfo> recoveryFileInfos = recoveryContext.getRecoveryFileInfos();
        for (RecoveryFileInfo fileInfo : recoveryFileInfos) {
            if (Boolean.TRUE.equals(fileInfo.getBackSuccess())) {
                String backFilePath = fileInfo.getBackFilePath();
                File backupFile = new File(backFilePath);
                if (backupFile.exists()) {
                    fileInfo.setBackFile(backupFile);
                    fileInfo.setBackFileFind(true);
                }
            }
            if (fileInfo.isCopySuccess()) {
                String targetFilePath = fileInfo.getTargetFilePath();
                File targetFile = new File(targetFilePath);
                if (targetFile.exists()) {
                    fileInfo.setTargetFile(targetFile);
                    fileInfo.setTargetFileFind(true);
                }
            }
        }
    }

    /**
     * 解析copyLog
     */
    private void parseCopyLog() {
        Path copyLogPathObject = recoveryContext.getCopyLogPathObject();
        CsvReadConfig csvReadConfig = new CsvReadConfig();
        CsvReader reader = new CsvReader(copyLogPathObject.normalize(), CharsetUtil.CHARSET_GBK, csvReadConfig);
        CsvData data = reader.read();
        Iterator<CsvRow> it = data.iterator();
        it.next();
        CsvRow metaInfo = it.next();
        String version = metaInfo.get(0);
        String datetime = metaInfo.get(1);
        String srcPath = metaInfo.get(2);
        String targetPath = metaInfo.get(3);
        String backupPath = metaInfo.get(4);
        recoveryContext.setBackPath(backupPath);
        recoveryContext.setVersion(version);
        recoveryContext.setSrcPath(srcPath);
        recoveryContext.setTargetPath(targetPath);

        log.info("解析出原始信息:\n\t版本:{},时间:{},srcPath:{},targetPath:{},backupPath:{}", version, datetime, srcPath, targetPath, backupPath);
        CsvRow head = it.next();
        List<RecoveryFileInfo> recoveryFileInfos = recoveryContext.getRecoveryFileInfos();
        while (it.hasNext()) {
            CsvRow row = it.next();
            RecoveryFileInfo info = new RecoveryFileInfo();
            recoveryFileInfos.add(info);
            info.setSrcFilePath(row.get(0));
            info.setCopySuccess(BooleanUtil.toBoolean(row.get(1)));
            info.setNeedBackup(BooleanUtil.toBoolean(row.get(2)));
            info.setBackSuccess(TwoDimensionalTableUtil.defaultValue2Boolean(row.get(3)));
            info.setBackFilePath(TwoDimensionalTableUtil.defaultValue2String(row.get(4)));
            info.setTargetFilePath(row.get(5));
        }
        log.info("已读取到copyLog");
        if (log.isDebugEnabled()) {
            log.debug("读取到copy日志里面的数据:{}", recoveryFileInfos);
        }
    }

    /**
     * 处理复制
     */
    private void dealCopy(Parameters params) {
        params.setCopyLogPath("./");
        log.info("进入复制模式, 源原件路径:{}, 目标路径:{}, 备份路径:{}, 日志路径:{}", params.getSrcPath(), params.getTargetPath(), params.getBackupDirectory(), params.getCopyLogPath());
        ValidatorUtils.valid(params, ValidConstant.Copy.class);
        String srcPath = params.getSrcPath();

        File file = new File(srcPath);
        if (!file.exists()) {
            throw new CopyException("路径[" + srcPath + "]没找到");
        }
        initCopyContext(params);
        dealRelativePath(copyContext);
        copy(file);
        printCopyLog();
    }

    /**
     * 初始化上下文
     */
    private void initCopyContext(Parameters params) {
        copyContext = new CopyContext();
        copyContext.setBackPath(params.getBackupDirectory());
        copyContext.setSrcPath(params.getSrcPath());
        copyContext.setTargetPath(params.getTargetPath());
        copyContext.setCopyLogPath(params.getCopyLogPath());
    }

    /**
     * 打印日志
     */
    private void printCopyLog() {
        String now = DateUtil.now();

        String csvPath = Paths.get(copyContext.getCopyLogPath(), COPY_LOG_NAME).toAbsolutePath().normalize().toString();
        CsvWriter csvWriter = new CsvWriter(csvPath, CharsetUtil.CHARSET_GBK);
        List<String[]> csvData = new ArrayList<>();
        csvData.add(new String[]{"文件名", "是否复制成功", "是否备份", "是否备份成功", "备份路径", "目标路径"});
        List<CopyFileOperateInfo> copyFileOperateInfos = copyContext.getCopyFileOperateInfos();
        int backErrorCount = 0;
        int copyErrorCount = 0;
        Collections.sort(copyFileOperateInfos, Comparator.reverseOrder());
        for (CopyFileOperateInfo info : copyFileOperateInfos) {
            String[] csvRow = new String[6];
            csvData.add(csvRow);

            boolean copySuccess = info.isCopySuccess();
            Boolean backSuccess = info.isBackSuccess();
            if (Boolean.FALSE.equals(copySuccess)) {
                copyErrorCount++;
            }
            if (Boolean.FALSE.equals(backSuccess)) {
                backErrorCount++;
            }

            csvRow[0] = TwoDimensionalTableUtil.defaultValue(info.getSrcFile().getPath());
            csvRow[1] = TwoDimensionalTableUtil.defaultValue(BooleanUtil.toStringYesNo(copySuccess));
            csvRow[2] = TwoDimensionalTableUtil.defaultValue(BooleanUtil.toStringYesNo(info.isNeedBackup()));
            csvRow[3] = TwoDimensionalTableUtil.defaultValue(backSuccess);
            csvRow[4] = TwoDimensionalTableUtil.defaultValue(FileUtil.getAbsolutePath(info.getBackFile()));
            csvRow[5] = TwoDimensionalTableUtil.defaultValue(info.getTargetFile().getPath());
        }

        csvWriter.write(new String[]{"复制器版本", "复制时间", "srcPath", "targetPath", "backupPath"});
        csvWriter.write(new String[]{"v1.0", now, copyContext.getSrcPath(), copyContext.getTargetPath(), copyContext.getBackPath()});
        csvWriter.writeComment(String.format("文件总数:%d; 复制失败数: %d; 备份失败数:%d", copyFileOperateInfos.size(), copyErrorCount, backErrorCount));

        for (String[] csvDatum : csvData) {
            csvWriter.write(csvDatum);
        }
        boolean success = backErrorCount + copyErrorCount == 0;
        if (success) {
            log.info("全部复制成功,详情见{}", csvPath);
        } else {
            log.info("复制有失败的之处, 详情请看日志:{}", csvPath);
        }
    }

    /**
     * 处理相对路径
     */
    private void dealRelativePath(BaseContext context) {
        String backupDirectory = context.getBackPath();
        String srcDirectory = context.getSrcPath();
        String targetDirectory = context.getTargetPath();

        String currentPath = PathUtil.toAbsNormal(Paths.get("./").toAbsolutePath()).toString();
        if (log.isDebugEnabled()) {
            log.debug("当前路径为:{}", currentPath);
        }

        Path backPath = Paths.get(backupDirectory);
        Path srcPath = Paths.get(srcDirectory);
        Path targetPath = Paths.get(targetDirectory);
        if (log.isDebugEnabled()) {
            log.debug("路径, src:{}, target:{}, backup:{}", srcPath, targetPath, backPath);
            log.debug("是否相对路径, src:{}, target:{}, backup:{}", srcPath.isAbsolute(), targetPath.isAbsolute(), backPath.isAbsolute());
        }

        if (!srcPath.isAbsolute()) {
            context.setSrcPath(PathUtil.toAbsNormal(Paths.get(currentPath, srcDirectory)).toString());
            if (log.isDebugEnabled()) {
                log.debug("发现相对路径,  {} - to - {}", srcDirectory, context.getSrcPath());
            }
        }

        if (!targetPath.isAbsolute()) {
            context.setTargetPath(PathUtil.toAbsNormal(Paths.get(currentPath, targetDirectory)).toString());
            if (log.isDebugEnabled()) {
                log.debug("发现相对路径,  {} - to - {}", targetDirectory, context.getTargetPath());
            }
        }

        if (!backPath.isAbsolute()) {
            context.setBackPath(PathUtil.toAbsNormal(Paths.get(currentPath, backupDirectory)).toString());
            if (log.isDebugEnabled()) {
                log.debug("发现相对路径,  {} - to - {}", backupDirectory, context.getBackPath());
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("文件准备工作完毕: {}", JSONUtil.toJsonPrettyStr(context));
        }
    }

    /**
     * 复制文件
     *
     * @param file
     */
    public void copy(File file) {
        beforeCopy(file);
        if (copyContext.isCurrentError()) {
            return;
        }

        if (copyContext.getCurrentSrcStatus() == FileStatus.DIRECTORY) {
            File[] files = file.listFiles();
            for (File child : files) {
                copy(child);
            }
        } else if (copyContext.getCurrentSrcStatus() == FileStatus.FILE) {
            List<CopyFileOperateInfo> copyFileOperateInfos = copyContext.getCopyFileOperateInfos();
            CopyFileOperateInfo copyFileOperateInfo = new CopyFileOperateInfo();
            copyFileOperateInfos.add(copyFileOperateInfo);
            copyFileOperateInfo.setSrcFile(copyContext.getCurrentSrcFile());
            copyFileOperateInfo.setTargetFile(copyContext.getCurrentTargetFile());

            if (copyContext.getCurrentTargetStatus() != FileStatus.NOT_EXIST) {
                copyFileOperateInfo.setNeedBackup(true);
                copyFileOperateInfo.setBackFile(copyContext.getCurrentBackFile());
            }
            copy_do(copyFileOperateInfo);
        } else {
            throw new CodeException("编码错误");
        }
    }

    /**
     * 具体复制
     */
    private void copy_do(CopyFileOperateInfo copyFileOperateInfo) {
        if (copyFileOperateInfo.isNeedBackup()) {
            copy_do_by_operation(copyFileOperateInfo, 2);
            if (copyFileOperateInfo.isBackSuccess()) {
                copy_do_by_operation(copyFileOperateInfo, 1);
            }
        } else {
            copy_do_by_operation(copyFileOperateInfo, 1);
        }
    }

    /**
     * 根据操作符号具体复制
     */
    private void copy_do_by_operation(CopyFileOperateInfo copyFileOperateInfo, int operationCode) {
        String message = null;
        File toFile = null;
        File fromFile = null;
        if (operationCode == 1) {
            message = "复制[";
            toFile = copyFileOperateInfo.getTargetFile();
            fromFile = copyFileOperateInfo.getSrcFile();
        } else {
            message = "备份[";
            toFile = copyFileOperateInfo.getBackFile();
            fromFile = copyFileOperateInfo.getTargetFile();
        }
        File copy = null;
        String errorInfo = null;
        try {
            message += FileUtil.getAbsolutePath(fromFile) + "]到[" + FileUtil.getAbsolutePath(toFile) + "]";
            copy = FileUtil.copy(fromFile, toFile, true);
        } catch (Exception e) {
            errorInfo = e.getMessage();
        }
        if (null == copy || !copy.exists()) {
            log.info(message + "失败");
            if (operationCode == 1) {
                copyFileOperateInfo.setCopySuccess(false);
            } else {
                copyFileOperateInfo.setBackSuccess(false);
            }
            copyFileOperateInfo.addErrorMessage(errorInfo);
        } else {
            log.info(message + "成功");
            if (operationCode == 1) {
                copyFileOperateInfo.setCopySuccess(true);
            } else {
                copyFileOperateInfo.setBackSuccess(true);
            }
        }
    }

    /**
     * 检查文件状态
     *
     * @param file 不能不存在
     */
    private void beforeCopy(File file) {
        if (!file.exists()) {
            throw new CodeException("目标文件不在, 代码错误");
        }
        if (!copyContext.isInited()) {
            init();
        }

        copyContext.setCurrentSrcFile(file);
        String absolutePath = FileUtil.getAbsolutePath(file);
        String srcPath = copyContext.getSrcPath();
        if (absolutePath.equals(srcPath)) {
            copyContext.setCurrentRelativePath(null);
        } else {
            if (!absolutePath.startsWith(srcPath + File.separator)) {
                throw new CodeException(String.format("目标文件[%s]在src[%s]外, 代码错误 ", absolutePath, srcPath));
            }
            String relativePath = absolutePath.substring(srcPath.length() + 1);
            int index = relativePath.lastIndexOf(File.separator);
            if (index > -1) {
                relativePath = relativePath.substring(0, index);
            } else {
                relativePath = null;
            }
            copyContext.setCurrentRelativePath(relativePath);
        }
        FileStatus filesStatus = getFilesStatus(file);
        copyContext.setCurrentSrcStatus(filesStatus);

        generateTargetAndBackPath();
        getTargetAndBackStatus();

        if (log.isDebugEnabled()) {
            log.debug("操作目标:{}", file.getAbsolutePath());
        }
    }

    /**
     * 初始化
     */
    private void init() {
        File srcFile = new File(copyContext.getSrcPath());
        if (srcFile.isDirectory()) {
            copyContext.setDirectoryCopy(true);
        }
        copyContext.setInited(true);
    }

    /**
     * 获取输出和备份的状态
     */
    private void getTargetAndBackStatus() {
        String currentTargetPath = copyContext.getCurrentTargetPath();
        File currentTargetFile = new File(currentTargetPath);
        String currentBackPath;
        String targetFileName = currentTargetFile.getName();
        String currentRelativePath = copyContext.getCurrentRelativePath();
        String backPath = copyContext.getBackPath();
        if (null == currentRelativePath) {
            currentBackPath = backPath + File.separator + targetFileName;
        } else {
            currentBackPath = backPath + File.separator + currentRelativePath + File.separator + targetFileName;
        }
        copyContext.setCurrentBackPath(currentBackPath);

        File currentBackFile = new File(currentBackPath);
        copyContext.setCurrentTargetFile(currentTargetFile);
        copyContext.setCurrentBackFile(currentBackFile);
        copyContext.setCurrentBackStatus(getFilesStatus(currentBackFile));
        copyContext.setCurrentTargetStatus(getFilesStatus(currentTargetFile));
    }

    /**
     * 生成输出和备份路径
     */
    private void generateTargetAndBackPath() {
        String srcName = copyContext.getCurrentSrcFile().getName();
        String currentRelativePath = copyContext.getCurrentRelativePath();
        String outPath = copyContext.getTargetPath();

        String currentTargetPath;
        if (null == currentRelativePath) {
            if (!copyContext.isDirectoryCopy()) {
                currentTargetPath = outPath;
            } else {
                currentTargetPath = outPath + File.separator + srcName;
            }
        } else {
            currentTargetPath = outPath + File.separator + currentRelativePath + File.separator + srcName;
        }
        copyContext.setCurrentTargetPath(currentTargetPath);
    }

    /**
     * 获取文件状态
     *
     * @param file
     * @return
     */
    private FileStatus getFilesStatus(File file) {
        if (null == file) {
            throw new CodeException("目标文件不在, 代码错误");
        }
        if (file.exists()) {
            return file.isDirectory() ? FileStatus.DIRECTORY : FileStatus.FILE;
        } else {
            return FileStatus.NOT_EXIST;
        }
    }


}
